const { execSync, exec } = require('child_process')
const fs = require('fs')
const path = require('path')
const archiver = require('archiver')
const { Client } = require('ssh2')
const dotenv = require('dotenv')

// === 环境加载 ===
const env = process.env.NODE_ENV || 'test' // 默认测试环境
dotenv.config({ path: `.env.${env}` })

// === 动态配置 ===
const branchFromArg = process.argv[2]
const BRANCH = branchFromArg || 'release'
const DIR = process.env.DIR

const config = {
  host: process.env.SERVER_HOST,
  port: process.env.SERVER_PORT || 22,
  username: process.env.SERVER_USERNAME,
  password: process.env.SERVER_PASSWORD,
  localFile: path.join(DIR, 'dist.zip'),
  remoteDir: process.env.REMOTE_DIR
}

// === 配置校验 ===
function checkEnvVars () {
  const requiredVars = [
    'DIR', 'SERVER_HOST', 'SERVER_USERNAME',
    'SERVER_PASSWORD', 'REMOTE_DIR', 'BUILD_COMMAND'
  ]
  requiredVars.forEach(varName => {
    if (!process.env[varName]) {
      exitWithError(`环境变量 ${varName} 未设置，请检查 .env.${env} 文件`)
    }
  })
}


// == 工具函数 ==
function exitWithError (msg) {
  console.error(msg)
  process.exit(1)
}

// == 步骤函数 ==
function ensureDirectoryExists (dir) {
  if (!fs.existsSync(dir)) exitWithError(`切换目录失败，目录${dir}不存在或不可访问！`)
  process.chdir(dir)
}

function checkBranchExists (branch) {
  try {
    execSync(`git rev-parse --verify ${branch}`, { stdio: 'ignore' })
    return true
  } catch {
    return false
  }
}

function gitCheckout (branch, exists) {
  try {
    if (exists) {
      console.log(`切换到分支: ${branch}...`)
      execSync(`git checkout ${branch}`, { stdio: 'inherit' })
    } else {
      console.log(`分支不存在，尝试从远程创建: ${branch}...`)
      execSync(`git checkout -b ${branch} origin/${branch}`, { stdio: 'inherit' })
    }
  } catch {
    exitWithError(`分支创建或切换失败，请检查！`)
  }
}

function pullLatest (branch) {
  try {
    console.log('拉取最新代码...')
    execSync(`git pull origin ${branch}`, { stdio: 'inherit' })
  } catch {
    exitWithError('Git pull 失败，请检查！')
  }
}

function buildProject () {
  try {
    console.log('开始构建，使用命令:', process.env.BUILD_COMMAND)
    execSync(process.env.BUILD_COMMAND, { stdio: 'inherit' })
    console.log('构建完成！')
  } catch {
    exitWithError('构建失败，请检查！')
  }
}

function zipDistFolder (dir) {
  const distPath = path.join(dir, 'dist')
  const zipPath = path.join(dir, 'dist.zip')

  if (!fs.existsSync(distPath)) exitWithError('dist 文件夹不存在，压缩失败！')
  // 若存在历史压缩包先删掉
  if (fs.existsSync(zipPath)) fs.unlinkSync(zipPath)

  return new Promise((resolve, reject) => {
    const output = fs.createWriteStream(zipPath)
    const archive = archiver('zip', { zlib: { level: 9 } })

    output.on('close', () => {
      console.log(`dist 文件夹已压缩为 ${zipPath}，共 ${archive.pointer()} 字节`)
      // 打开资源管理器，方便查找生成的 dist.zip 文件
      // exec(`explorer "${DIR}"`);
      resolve(zipPath)
    })
    archive.on('error', err => reject(err))
    archive.pipe(output)
    archive.directory(distPath, 'dist')
    archive.finalize()
  })
}

async function uploadAndUnzipOnServer (cfg) {
  return new Promise((resolve, reject) => {
    const conn = new Client()
    conn.on('ready', () => {
      console.log('SSH 连接成功，准备上传...')
      conn.sftp((err, sftp) => {
        if (err) return reject(err)
        const remoteFilePath = `${cfg.remoteDir}/${path.basename(cfg.localFile)}`
        sftp.fastPut(cfg.localFile, remoteFilePath, uploadErr => {
          if (uploadErr) return reject(uploadErr)
          console.log('文件上传成功')
          // 解压并输出
          const cmd = [
            `cd ${cfg.remoteDir}`,
            `unzip -o ${path.basename(cfg.localFile)}`
          ].join(' && ')
          conn.exec(cmd, { pty: true }, (execErr, stream) => {
            if (execErr) return reject(execErr)
            stream.on('close', () => {
              console.log('解压完成')
              conn.end()
              resolve()
            }).on('data', data => process.stdout.write(data))
              .stderr.on('data', data => process.stderr.write(data))
          })
        })
      })
    })
    conn.on('error', reject)
    conn.on('end', () => console.log('部署完成，连接已关闭'))
    conn.connect(cfg)
  })
}


// == 部署主流程 ==
async function main () {
  checkEnvVars() // 配置校验
  ensureDirectoryExists(DIR)
  const branchExists = checkBranchExists(BRANCH)
  gitCheckout(BRANCH, branchExists)
  pullLatest(BRANCH)
  buildProject()
  await zipDistFolder(DIR).catch(err => exitWithError(`压缩dist文件夹失败: ${err}`))
  console.log('准备连接服务器...')
  await uploadAndUnzipOnServer(config).catch(err => exitWithError(`上传或解压失败: ${err}`))
}

main()